#include "tstranscription_factor.h"
#include <stdlib.h>
#include <glib-object.h>

typedef struct _TsTranscriptionFactor {
  GObject parent_instance;
  GString *name;  // 转录因子名称
  GList *bound_genes;  // 绑定到的基因列表

  gboolean status;
  gint port;
  gchar *id_str;
  gchar *port_str;
  gchar *ip;
  gchar *user;
  gchar *pwd;
  gchar *client_id;
  GObject son_instance;
  GObject next_instance;
} TsTranscriptionFactor;
enum {
  PROP_0, PROP_STATUS, PROP_PORT,
  PROP_ID_STR, PROP_PORT_STR, PROP_IP, PROP_USER, PROP_PWD, PROP_CLIENT_ID,
  PROP_SON, PROP_NEXT, N_PROPERTIES };

static GParamSpec *properties[N_PROPERTIES] = { NULL, };

G_DEFINE_TYPE (TsTranscriptionFactor, ts_transcription_factor, G_TYPE_OBJECT)

static void
ts_transcription_factor_set_status (TsTranscriptionFactor *obj,
                     gboolean    status)
{
  status = !!status;

  if (obj->status != status)
    {
      obj->status = status;

      g_assert (properties[PROP_STATUS] != NULL);
      g_object_notify_by_pspec (G_OBJECT (obj), properties[PROP_STATUS]);
    }
}

static void
ts_transcription_factor_set_port (TsTranscriptionFactor *obj,
                     gint        port)
{
  if (obj->port != port)
    {
      obj->port = port;

      g_assert (properties[PROP_PORT] != NULL);
      g_object_notify_by_pspec (G_OBJECT (obj), properties[PROP_PORT]);
    }
}

static void
ts_transcription_factor_set_id_str (TsTranscriptionFactor  *obj,
                     const gchar *id_str)
{
  if (g_strcmp0 (obj->id_str, id_str) != 0)
    {
      g_free (obj->id_str);
      obj->id_str = g_strdup (id_str);

      g_assert (properties[PROP_ID_STR] != NULL);
      g_object_notify_by_pspec (G_OBJECT (obj), properties[PROP_ID_STR]);
    }
}

static void
ts_transcription_factor_set_port_str (TsTranscriptionFactor  *obj,
                     const gchar *port_str)
{
  if (g_strcmp0 (obj->port_str, port_str) != 0)
    {
      g_free (obj->port_str);
      obj->port_str = g_strdup (port_str);
      obj->port = atoi (port_str);

      g_assert (properties[PROP_PORT_STR] != NULL);
      g_object_notify_by_pspec (G_OBJECT (obj), properties[PROP_PORT_STR]);
    }
}

static void
ts_transcription_factor_set_ip (TsTranscriptionFactor  *obj,
                     const gchar *ip)
{
  if (g_strcmp0 (obj->ip, ip) != 0)
    {
      g_free (obj->ip);
      obj->ip = g_strdup (ip);

      g_assert (properties[PROP_IP] != NULL);
      g_object_notify_by_pspec (G_OBJECT (obj), properties[PROP_IP]);
    }
}

static void
ts_transcription_factor_set_user (TsTranscriptionFactor  *obj,
                      const gchar *user)
{
  if (g_strcmp0 (obj->user, user) != 0)
    {
      g_free (obj->user);
      obj->user = g_strdup (user);

      g_assert (properties[PROP_USER] != NULL);
      g_object_notify_by_pspec (G_OBJECT (obj), properties[PROP_USER]);
    }
}

static void
ts_transcription_factor_set_pwd (TsTranscriptionFactor  *obj,
                      const gchar *pwd)
{
  if (g_strcmp0 (obj->pwd, pwd) != 0)
    {
      g_free (obj->pwd);
      obj->pwd = g_strdup (pwd);

      g_assert (properties[PROP_PWD] != NULL);
      g_object_notify_by_pspec (G_OBJECT (obj), properties[PROP_PWD]);
    }
}

static void
ts_transcription_factor_set_client_id (TsTranscriptionFactor  *obj,
                      const gchar *client_id)
{
  if (g_strcmp0 (obj->client_id, client_id) != 0)
    {
      g_free (obj->client_id);
      obj->client_id = g_strdup (client_id);

      g_assert (properties[PROP_CLIENT_ID] != NULL);
      g_object_notify_by_pspec (G_OBJECT (obj), properties[PROP_CLIENT_ID]);
    }
}

static void
ts_transcription_factor_finalize (GObject *gobject)
{
  TsTranscriptionFactor *self = (TsTranscriptionFactor *) gobject;

  g_free (self->ip);
  g_free (self->user);
  g_free (self->pwd);
  g_free (self->client_id);

  g_object_notify (gobject, "port");
  g_object_notify_by_pspec (gobject, properties[PROP_STATUS]);

  G_OBJECT_CLASS (ts_transcription_factor_parent_class)->finalize (gobject);
}

static void
ts_transcription_factor_set_property (GObject *gobject,
                          guint prop_id,
                          const GValue *value,
                          GParamSpec *pspec)
{
  TsTranscriptionFactor *tobj = (TsTranscriptionFactor *) gobject;

  g_assert_cmpint (prop_id, !=, 0);
  g_assert_cmpint (prop_id, !=, N_PROPERTIES);
  g_assert (pspec == properties[prop_id]);

  switch (prop_id)
    {
    case PROP_STATUS:
      ts_transcription_factor_set_status (tobj, g_value_get_boolean (value));
      break;
    case PROP_PORT:
      ts_transcription_factor_set_port (tobj, g_value_get_int (value));
      break;
    case PROP_ID_STR:
      ts_transcription_factor_set_id_str (tobj, g_value_get_string (value));
      break;
    case PROP_PORT_STR:
      ts_transcription_factor_set_port_str (tobj, g_value_get_string (value));
      break;
    case PROP_IP:
      ts_transcription_factor_set_ip (tobj, g_value_get_string (value));
      break;
    case PROP_USER:
      ts_transcription_factor_set_user (tobj, g_value_get_string (value));
      break;
    case PROP_PWD:
      ts_transcription_factor_set_pwd (tobj, g_value_get_string (value));
      break;
    case PROP_CLIENT_ID:
      ts_transcription_factor_set_client_id (tobj, g_value_get_string (value));
      break;

    default:
      g_assert_not_reached ();
    }
}

static void
ts_transcription_factor_get_property (GObject *gobject,
                          guint prop_id,
                          GValue *value,
                          GParamSpec *pspec)
{
  TsTranscriptionFactor *tobj = (TsTranscriptionFactor *) gobject;

  g_assert_cmpint (prop_id, !=, 0);
  g_assert_cmpint (prop_id, !=, N_PROPERTIES);
  g_assert (pspec == properties[prop_id]);

  switch (prop_id)
    {
    case PROP_PORT:
      g_value_set_int (value, tobj->port);
      break;

    case PROP_STATUS:
      g_value_set_boolean (value, tobj->status);
      break;

    case PROP_IP:
      g_value_set_string (value, tobj->ip);
      break;

    case PROP_USER:
      g_value_set_string (value, tobj->user);
      break;

    case PROP_PWD:
      g_value_set_string (value, tobj->pwd);
      break;

    case PROP_CLIENT_ID:
      g_value_set_string (value, tobj->client_id);
      break;

    default:
      g_assert_not_reached ();
    }
}

static void
ts_transcription_factor_class_init (TsTranscriptionFactorClass *klass)
{
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);

  properties[PROP_STATUS] = g_param_spec_int ("status", "Status", "Status",
      -1, G_MAXINT, 0, G_PARAM_READWRITE);
  properties[PROP_PORT] = g_param_spec_int ("port", "Port", "Port",
      -1, G_MAXINT, 0, G_PARAM_READWRITE);
  properties[PROP_ID_STR] = g_param_spec_string ("id_str", "IdStr", "IdStr",
      NULL, G_PARAM_READWRITE);
  properties[PROP_PORT_STR] = g_param_spec_string ("port_str", "PortStr", "PortStr",
      NULL, G_PARAM_READWRITE);
  properties[PROP_IP] = g_param_spec_string ("ip", "Ip", "Ip",
      NULL, G_PARAM_READWRITE);
  properties[PROP_USER] = g_param_spec_string ("user", "user", "user",
      NULL, G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
  properties[PROP_PWD] = g_param_spec_string ("pwd", "pwd", "pwd",
      NULL, G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
  properties[PROP_CLIENT_ID] = g_param_spec_string ("client_id", "client_id",
      "client_id", NULL, G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
  properties[PROP_SON] = g_param_spec_object ("son", "son", "son",
      G_TYPE_OBJECT, G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
  properties[PROP_NEXT] = g_param_spec_object ("next", "next", "next",
      G_TYPE_OBJECT, G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);

  gobject_class->set_property = ts_transcription_factor_set_property;
  gobject_class->get_property = ts_transcription_factor_get_property;
  gobject_class->finalize = ts_transcription_factor_finalize;

  g_object_class_install_properties (gobject_class, N_PROPERTIES, properties);
}

static void
ts_transcription_factor_init (TsTranscriptionFactor *self)
{
  self->status = TRUE;
  self->port = 1883;
  self->ip = g_strdup ("0.0.0.0");
  self->id_str = NULL;
  self->user = NULL;
  self->pwd = NULL;
  self->client_id = NULL;
}

TsTranscriptionFactor *ts_transcription_factor_new (void)
{
  return g_object_new (TS_TRANSCRIPTION_FACTOR_TYPE, NULL);
}
